#ifndef rate_controller_HH
#define rate_controller_HH 1

#include "component.hh"
#include "config.h"
#include "netinet++/ethernet.hh"
#include "netinet++/datapathid.hh"
#include <xercesc/dom/DOM.hpp>
#include "routing/routing.hh"

#ifdef LOG4CXX_ENABLED
#include <boost/format.hpp>
#include "log4cxx/logger.h"
#else                   
#include "vlog.hh"
#endif
#include "fnv_hash.hh"
#include "linkdb/linkdb.hh"

#include <string>
#include "nox.hh"
#include "flow.hh"

#define RATE_MSG_ETHR_TYPE 0x8811
#define CUR_VERSION 0

using namespace std;
using namespace vigil::container;
namespace vigil {
namespace applications{

struct RateMsg {
	ethernetaddr dst_mac;	/* switch port's MAC address */
	ethernetaddr src_mac;	/* the sender's MAC address */
	uint16_t type;		/* ethernet type: RATE_MSG_ETHR_TYPE */
	uint16_t ver;		/* protocol version */
	uint32_t src_ip;	/* flow: src ip address */
	uint32_t dst_ip;        /* flow: dst ip address */
	uint16_t pad;
	uint16_t proto_tp;	/* transport layer protocol */
	uint16_t src_tp;        /* flow: transport layer src port number */
	uint16_t dst_tp;        /* flow: transport layer dst port number*/
	uint64_t rate;		/* rate in bps. this will be changed to
				 * leaky bucket params in next version */
	uint8_t unused[26];
};

class RateEntry{
	public:
	uint64_t rate;
	datapathid dp;
	uint16_t inport;
};

class rate_controller
	: public container::Component {
  
  public:
	/** Constructor.
	* @param c context as required by Component
	* @param node Xercesc DOMNode
	*/
	rate_controller(const Context* c, const xercesc::DOMNode*);

	/** Destructor.
	 */
	~rate_controller();

	/** Configure component
	 * Register events.
	 * @param config configuration
	 */
	void configure(const Configuration* config);

	/** Start component.
	*/
	void install() 
	{}
	uint32_t hash_flow(ofp_match* ofm);
	uint32_t hash_flow(Flow flow);
	Disposition handle_flow_in(const Event& e);
	Disposition handle_flow_expired(const Event& e);
	static void getInstance(const container::Context* ctxt, rate_controller*& ofp); 

	typedef boost::shared_ptr<RateEntry> RateEntryPtr;
	typedef hash_map<uint32_t, RateEntryPtr> RateTable;
	RateTable rate_table;
	bool updateRate(uint32_t hash_value, uint64_t rate);
	uint64_t getRate(uint32_t hash_value);
	bool addRateEntry(uint32_t hash_vale, uint64_t rate, datapathid dp, uint16_t port);
	bool getRateEntry(uint32_t hash_value, RateEntryPtr& rep);
	bool delRateEntry(uint32_t hash_value);
	bool addRateEntry(uint32_t hash_vale, RateEntryPtr new_entry);

  private:
	Routing_module::RoutePtr empty;
	LinkDB *linkdb;
	Routing_module *routing;

	void reportRate(const datapathid& dpid, const Flow& flow, uint64_t rate);

	bool set_route(Flow_in_event& fi,
                     Routing_module::RoutePtr& route,
                     uint16_t& inport, uint16_t& outport,
                     const Buffer& actions, bool check_nat);

	bool setup_route(Flow flow, Routing_module::Route route,
			 uint16_t ap_inport, uint16_t ap_outport,
                         uint16_t flow_timeout);
	
	bool print_route(const Flow& flow, const Routing_module::Route& route, 
			 uint16_t ap_inport, uint16_t ap_outport);
  };
 };
};

#endif
